<?php
namespace tjsd\system\enviroment;

/**
 * Class is responsible for autoloading classes.
 * 
 * ClassLoader itself doesn't look for class files, it uses
 * objects of \tjsd\mappers\Index to locate class files.
 * 
 * You may use as many Indexes you want. When first index doesn't find location
 * of file, next one is used etc.
 * 
 * @author Jakub Tesárek <info@tjsd.cz>
 * @copyright 2012
 * @version 1.0
 */
final class ClassLoader extends \tjsd\core\Object {
	
	/**
	 * Separator of namespaces 
	 */
	const NAMESPACE_SEPARATOR = '\\';
	
	/**
	 * List of all indexes in correct order
	 * 
	 * @var array 
	 */
	private $indexes;
	
	/**
	 * Creates new ClassLoader.
	 * 
	 * Class loader isn't registered via spl_autoload_register yet.
	 * 
	 * You may assign initial Index as  parameter.
	 * 
	 * @see self::register()
	 * @param \tjsd\mappers\Index $index	initial index
	 */
	public function __construct(\tjsd\mappers\Index $index = null) {
		$this->indexes = array();
		if(!is_null($index)) {
			$this->addClassIndex($index);
		}
	}
	
	/**
	 * Adds new index to the end of indexes used to find class files
	 * 
	 * @param \tjsd\mappers\Index $index	new index to be used
	 */
	public function addClassIndex(\tjsd\mappers\Index $index) {
		$this->indexes[] = $index;
	}
	
	/**
	 * Tries to find and include class file containing required class
	 * 
	 * This method can be used without registering ClassLoader as autoloader.
	 * 
	 * @see self::register()
	 * @param string $className	class name including namespaces
	 * @return bool					returns true if class file was found and included
	 */
	public function loadClass($className) {
		if(!empty($this->indexes)) {
			$path = explode(self::NAMESPACE_SEPARATOR, $className);
			foreach($this->indexes as $index) {
				//ask all indexes until any of them finds the class file
				$filePath = $index->find($path);
				if(!empty($filePath)) {
					$realPath  = DOCUMENT_ROOT . DIRECTORY_SEPARATOR . $filePath;
					if(file_exists($realPath)) {
						require_once($realPath);
						return true;
					}
				}
			}
		} else {
			return false;
		}
	}
	
	/**
	 * Register autoloader to be called whenever undefined class is needed.
	 * 
	 * @param bool $prepand		if true, this autoloader will be used as firt in stack of all autoloader, as last otherwise
	 */
	public function register($prepand = false) {
		$that = $this;
		spl_autoload_register(function($className) use ($that) {
			$that->loadClass($className); 
		}, true, $prepand);
	}
}